package com.wl.lib.widget

import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isGone
import androidx.recyclerview.widget.RecyclerView

// Created by wangliang on 2024/4/26.
open class RecyclerAdapterWrapper<VH : RecyclerView.ViewHolder>(
    val innerAdapter: RecyclerView.Adapter<VH>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val headerViews: MutableList<FixedViewInfo> = mutableListOf()
    private val footerViews: MutableList<FixedViewInfo> = mutableListOf()

    fun addHeaderView(headerView: View) {
        headerViews.add(
            FixedViewInfo(
                headerView,
                HEADER_VIEW_TYPE_BASE + headerViews.size
            )
        )
        notifyDataSetChanged()
    }

    fun addFooterView(footerView: View) {
        footerViews.add(
            FixedViewInfo(
                footerView,
                FOOTER_VIEW_TYPE_BASE + footerViews.size
            )
        )
        notifyDataSetChanged()
    }

    fun containHeaderView(headerView: View): Boolean {
        return headerViews.find { it.view === headerView } != null
    }

    fun containFooterView(footerView: View): Boolean {
        return footerViews.find { it.view === footerView } != null
    }

    fun removeHeaderView(headerView: View): Boolean {
        return headerViews.find { it.view === headerView }?.let {
            headerViews.remove(it)
            notifyDataSetChanged()
            true
        } ?: false
    }

    fun removeFooterView(footerView: View): Boolean {
        return footerViews.find { it.view === footerView }?.let {
            footerViews.remove(it)
            notifyDataSetChanged()
            true
        } ?: false
    }

    fun removeAllHeaderView() {
        headerViews.clear()
        notifyDataSetChanged()
    }

    fun removeAllFooterView() {
        footerViews.clear()
        notifyDataSetChanged()
    }

    val headerCount: Int
        get() = headerViews.size

    val footerCount: Int
        get() = footerViews.size

    var clipChildrenForHeaderFooterView: Boolean = true
    var clipToPaddingForHeaderFooterView: Boolean = true

    override fun getItemViewType(position: Int): Int {
        return when {
            isHeaderPosition(position) -> headerViews[position].viewType
            isFooterPosition(position) -> footerViews[position - headerViews.size - innerAdapter.itemCount].viewType
            else -> innerAdapter.getItemViewType(actualPosition(position))
        }
    }

    private fun isHeaderPosition(position: Int): Boolean = position < headerViews.size

    private fun isFooterPosition(position: Int): Boolean = position >= headerViews.size + innerAdapter.itemCount

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when {
            isHeaderViewType(viewType) -> {
                createHeaderFooterViewHolder(headerViews[viewType - HEADER_VIEW_TYPE_BASE].view)
            }
            isFooterViewType(viewType) -> {
                createHeaderFooterViewHolder(footerViews[viewType - FOOTER_VIEW_TYPE_BASE].view)
            }
            else -> innerAdapter.createViewHolder(parent, viewType)
        }
    }

    private fun isHeaderViewType(viewType: Int): Boolean =
        viewType >= HEADER_VIEW_TYPE_BASE && viewType < HEADER_VIEW_TYPE_BASE + headerViews.size

    private fun isFooterViewType(viewType: Int): Boolean =
        viewType >= FOOTER_VIEW_TYPE_BASE && viewType < FOOTER_VIEW_TYPE_BASE + footerViews.size

    private fun createHeaderFooterViewHolder(view: View): RecyclerView.ViewHolder {
        return object : RecyclerView.ViewHolder(FrameLayout(view.context)) {}
    }

    override fun getItemCount(): Int = headerViews.size + innerAdapter.itemCount + footerViews.size

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (!isHeaderPosition(position) && !isFooterPosition(position)) {
            @Suppress("UNCHECKED_CAST")
            innerAdapter.onBindViewHolder(holder as VH, actualPosition(position))
        } else {
            val containerView = (holder.itemView as? FrameLayout) ?: return
            containerView.clipChildren = clipChildrenForHeaderFooterView
            containerView.clipToPadding = clipToPaddingForHeaderFooterView
            val innerView = when {
                isHeaderPosition(position) -> headerViews[position].view
                isFooterPosition(position) -> footerViews[position - headerViews.size - innerAdapter.itemCount].view
                else -> return
            }
            if (containerView.getChildAt(0) === innerView || innerView.isGone) {
                return
            }
            if (containerView.layoutParams == null) {
                containerView.layoutParams = RecyclerView.LayoutParams(
                    RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
                )
            }
            containerView.layoutParams.apply {
                width = innerView.layoutParams.width
                height = innerView.layoutParams.height
            }
            (innerView.parent as? ViewGroup)?.removeView(innerView)
            containerView.apply {
                removeAllViews()
                addView(innerView)
            }
        }
    }

    private fun actualPosition(position: Int): Int = position - headerViews.size

    override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) {
        super.registerAdapterDataObserver(observer)
        innerAdapter.registerAdapterDataObserver(observer)
    }

    override fun unregisterAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) {
        super.unregisterAdapterDataObserver(observer)
        innerAdapter.unregisterAdapterDataObserver(observer)
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        innerAdapter.onAttachedToRecyclerView(recyclerView)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        innerAdapter.onDetachedFromRecyclerView(recyclerView)
    }

    companion object {

        private const val HEADER_VIEW_TYPE_BASE = -1 shl 10
        private const val FOOTER_VIEW_TYPE_BASE = -1 shl 11

        private class FixedViewInfo(val view: View, val viewType: Int)
    }
}
